package com.tbynet.jwp.admin.profile;

import com.jfinal.aop.Inject;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.ehcache.CacheKit;
import com.tbynet.jwp.admin.AdminController;
import com.tbynet.jwp.framework.kit.PassKit;
import com.tbynet.jwp.service.spi.UserManager;
import com.tbynet.jwp.model.Usermeta;
import com.tbynet.jwp.model.Users;
import com.tbynet.jwp.repository.spi.UserService;

import java.util.ArrayList;
import java.util.List;

/**
 * 个人资料管理控制器
 *
 * 核心职责：
 * 1. 当前登录用户的个人资料查看和编辑
 * 2. 用户基本信息更新
 * 3. 用户偏好设置管理
 * 4. 密码修改功能
 *
 * 设计原则：
 * - 只操作当前登录用户的数据
 * - 严格的数据验证和权限控制
 * - 完整的错误处理和用户反馈
 * - 安全的密码修改机制
 *
 * @author 佰亿互联
 * @version 3.0
 * @since 2025-11-04
 */
public class ProfileAdminController extends AdminController {

    // ========== 依赖注入 ==========

    /** 用户管理编排层 - 用于处理用户资料更新业务逻辑 */
    @Inject
    private UserManager userManager;

    /** 用户服务层 - 用于用户数据操作 */
    @Inject
    private UserService userService;

    // ========== 页面渲染方法 ==========

    /**
     * 个人资料页面
     *
     * 功能说明：
     * - 显示当前登录用户的个人资料
     * - 加载用户的完整信息和元数据
     * - 需要用户登录权限
     *
     * 访问路径：GET /admin/profile
     */
    public void index() {
        long startTime = System.currentTimeMillis();

        try {
            logOperation("VIEW_PROFILE", "查看个人资料", "开始", null);

            Users user = getCurrentLoginUser();
            if (user == null) {
                log.warn("访问个人资料页面失败：用户未登录");
                redirectToLogin("/admin/profile");
                return;
            }

            // 加载用户的元数据
            loadUserMetaData(user);
            set("user", user);

            render("index.html");

            logOperation("VIEW_PROFILE", "查看个人资料", "成功",
                    "用户ID: " + user.getID());

        } catch (Exception e) {
            logOperation("VIEW_PROFILE", "查看个人资料", "失败", e.getMessage());
            handleSystemException(e, "加载个人资料");
        } finally {
            log.debug("个人资料页面加载完成，耗时: {}ms", System.currentTimeMillis() - startTime);
        }
    }

    // ========== 数据操作方法 ==========

    /**
     * 更新个人资料
     *
     * 功能说明：
     * - 更新当前登录用户的个人资料
     * - 支持基本信息、联系信息、偏好设置更新
     * - 支持密码修改
     *
     * 访问路径：POST /admin/profile/update
     */
    public void update() {
        long startTime = System.currentTimeMillis();

        try {
            logOperation("UPDATE_PROFILE", "更新个人资料", "开始", null);

            Users user = getCurrentLoginUser();
            if (user == null) {
                fail("用户未登录");
                return;
            }

            // 参数验证
            if (!validateProfileParams()) {
                return;
            }

            // 更新用户信息
            updateUserFromParams(user);
            List<Usermeta> metas = buildProfileMetas(user);

            // 调用Manager层更新用户信息
            Ret result = userManager.updateUser(user, metas);
            if (result.isOk()) {
                // 更新缓存中的用户信息
                updateUserCache(user);

                logOperation("UPDATE_PROFILE", "更新个人资料", "成功",
                        "用户ID: " + user.getID());
                ok(Ret.by("msg", "更新个人资料成功").set("data", user.getID()));
            } else {
                logOperation("UPDATE_PROFILE", "更新个人资料", "失败",
                        "用户ID: " + user.getID());
                fail("更新个人资料失败，请联系管理员");
            }

        } catch (Exception e) {
            logOperation("UPDATE_PROFILE", "更新个人资料", "异常", e.getMessage());
            handleSystemException(e, "更新个人资料");
        } finally {
            log.debug("个人资料更新处理完成，耗时: {}ms", System.currentTimeMillis() - startTime);
        }
    }

    /**
     * 修改密码
     *
     * 功能说明：
     * - 修改当前登录用户的密码
     * - 验证旧密码的正确性
     * - 新密码强度验证
     *
     * 访问路径：POST /admin/profile/changePassword
     */
    public void changePassword() {
        long startTime = System.currentTimeMillis();

        try {
            logOperation("CHANGE_PASSWORD", "修改密码", "开始", null);

            Users user = getCurrentLoginUser();
            if (user == null) {
                fail("用户未登录");
                return;
            }

            // 获取参数
            String oldPassword = getPara("old_password");
            String newPassword = getPara("new_password");
            String confirmPassword = getPara("confirm_password");

            // 参数验证
            if (!validatePasswordParams(oldPassword, newPassword, confirmPassword)) {
                return;
            }

            // 验证旧密码
            if (!validateOldPassword(user, oldPassword)) {
                return;
            }

            // 更新密码
            if (updateUserPassword(user, newPassword)) {
                logOperation("CHANGE_PASSWORD", "修改密码", "成功",
                        "用户ID: " + user.getID());
                ok(Ret.by("msg", "密码修改成功"));
            } else {
                logOperation("CHANGE_PASSWORD", "修改密码", "失败",
                        "用户ID: " + user.getID());
                fail("密码修改失败，请联系管理员");
            }

        } catch (Exception e) {
            logOperation("CHANGE_PASSWORD", "修改密码", "异常", e.getMessage());
            handleSystemException(e, "修改密码");
        } finally {
            log.debug("密码修改处理完成，耗时: {}ms", System.currentTimeMillis() - startTime);
        }
    }

    // ========== 私有方法：核心逻辑 ==========

    /**
     * 获取当前登录用户
     *
     * @return 当前登录用户对象，未登录返回null
     */
    private Users getCurrentLoginUser() {
        return getLoginUser();
    }

    /**
     * 加载用户元数据
     *
     * @param user 用户对象
     */
    private void loadUserMetaData(Users user) {
        long startTime = System.currentTimeMillis();

        try {
            List<Usermeta> metas = userService.getUserMetas(user.getID());
            for (Usermeta meta : metas) {
                try {
                    if (Usermeta.session_tokens.equals(meta.getMetaKey())) {
                        user.put(meta.getMetaKey(), meta.getSessionTokens());
                    } else {
                        user.put(meta.getMetaKey(), meta.getMetaValue());
                    }
                } catch (Exception e) {
                    log.warn("加载用户元数据失败，用户ID: {}, 元数据键: {}",
                            user.getID(), meta.getMetaKey(), e);
                    // 单个元数据加载失败不影响整体
                }
            }

            log.debug("用户元数据加载完成，用户ID: {}, 数量: {}, 耗时: {}ms",
                    user.getID(), metas.size(), System.currentTimeMillis() - startTime);

        } catch (Exception e) {
            log.error("加载用户元数据失败，用户ID: {}", user.getID(), e);
        }
    }

    /**
     * 验证个人资料参数
     *
     * @return 验证是否通过
     */
    private boolean validateProfileParams() {
        String email = getPara("email");
        String userPass = getPara("user_pass");

        // 必需参数验证
        if (!validateRequired("email", "电子邮件")) {
            return false;
        }

        // 邮箱格式验证
        if (!validateEmail(email, "电子邮件")) {
            return false;
        }

        // 密码长度验证（如果提供了密码）
        if (StrKit.notBlank(userPass) && userPass.length() < 6) {
            handleParamError("user_pass", "密码长度不能少于6位");
            return false;
        }

        return true;
    }

    /**
     * 验证密码参数
     *
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     * @param confirmPassword 确认密码
     * @return 验证是否通过
     */
    private boolean validatePasswordParams(String oldPassword, String newPassword, String confirmPassword) {
        // 必需参数验证
        if (!validateRequired("old_password", "旧密码")) return false;
        if (!validateRequired("new_password", "新密码")) return false;
        if (!validateRequired("confirm_password", "确认密码")) return false;

        // 密码长度验证
        if (!validateLength(newPassword, 6, 100, "新密码")) return false;

        // 密码一致性验证
        if (!newPassword.equals(confirmPassword)) {
            handleParamError("confirm_password", "新密码和确认密码不一致");
            return false;
        }

        // 新旧密码不能相同
        if (oldPassword.equals(newPassword)) {
            handleParamError("new_password", "新密码不能与旧密码相同");
            return false;
        }

        return true;
    }

    /**
     * 验证旧密码
     *
     * @param user 用户对象
     * @param oldPassword 旧密码
     * @return 验证是否通过
     */
    private boolean validateOldPassword(Users user, String oldPassword) {
        try {
            // 从存储的密码中提取盐值
            String salt = PassKit.getSalt(user.getUserPass());
            // 使用相同盐值加密输入密码
            String hashedPassword = PassKit.encrypt(oldPassword, salt);
            // 对比加密结果
            boolean isValid = user.getUserPass().equals(hashedPassword);

            if (!isValid) {
                handleParamError("old_password", "旧密码不正确");
            }

            return isValid;

        } catch (Exception e) {
            log.error("验证旧密码异常，用户ID: {}", user.getID(), e);
            handleParamError("old_password", "密码验证失败");
            return false;
        }
    }

    /**
     * 从参数更新用户信息
     *
     * @param user 用户对象
     */
    private void updateUserFromParams(Users user) {
        String displayName = getPara("display_name");
        String email = getPara("email");
        String url = getPara("url", "");
        String userPass = getPara("user_pass");

        // 更新基本信息
        user.setDisplayName(displayName);
        user.setUserEmail(email);
        user.setUserUrl(url);

        // 如果提供了新密码，则更新密码
        if (StrKit.notBlank(userPass)) {
            user.setUserPass(PassKit.encrypt(userPass));
        }
    }

    /**
     * 更新用户密码
     *
     * @param user 用户对象
     * @param newPassword 新密码
     * @return 更新是否成功
     */
    private boolean updateUserPassword(Users user, String newPassword) {
        try {
            // 加密新密码
            user.setUserPass(PassKit.encrypt(newPassword));

            // 调用Manager层更新用户
            Ret result = userManager.updateUser(user, new ArrayList<>());
            return result.isOk();

        } catch (Exception e) {
            log.error("更新用户密码异常，用户ID: {}", user.getID(), e);
            return false;
        }
    }

    /**
     * 构建个人资料元数据
     *
     * @param user 用户对象
     * @return 元数据列表
     */
    private List<Usermeta> buildProfileMetas(Users user) {
        List<Usermeta> metas = new ArrayList<>();

        // 基本信息元数据
        addProfileMetaIfPresent(metas, user, Usermeta.first_name, getPara("first_name"));
        addProfileMetaIfPresent(metas, user, Usermeta.last_name, getPara("last_name"));
        addProfileMetaIfPresent(metas, user, Usermeta.nickname, getPara("nickname"));
        addProfileMetaIfPresent(metas, user, Usermeta.locale, getPara("locale"));
        addProfileMetaIfPresent(metas, user, Usermeta.description, getPara("description"));
        addProfileMetaIfPresent(metas, user, Usermeta.admin_color, getPara("admin_color"));
        addProfileMetaIfPresent(metas, user, Usermeta.rich_editing, getPara("rich_editing"));
        addProfileMetaIfPresent(metas, user, Usermeta.syntax_highlighting, getPara("syntax_highlighting"));
        addProfileMetaIfPresent(metas, user, Usermeta.comment_shortcuts, getPara("comment_shortcuts"));
        addProfileMetaIfPresent(metas, user, Usermeta.show_admin_bar_front, getPara("admin_bar_front"));
        addProfileMetaIfPresent(metas, user, Usermeta.simple_local_avatar, getPara("simple_local_avatar"));

        log.debug("构建个人资料元数据完成，用户ID: {}, 元数据数量: {}", user.getID(), metas.size());
        return metas;
    }

    // ========== 私有方法：辅助工具 ==========

    /**
     * 如果参数存在则添加个人资料元数据
     */
    private void addProfileMetaIfPresent(List<Usermeta> metas, Users user, String metaKey, String metaValue) {
        if (StrKit.notBlank(metaValue)) {
            Usermeta meta = getOrCreateUserMeta(user, metaKey);
            setMetaValueByKey(meta, metaKey, metaValue);
            metas.add(meta);
        }
    }

    /**
     * 获取或创建用户元数据
     */
    private Usermeta getOrCreateUserMeta(Users user, String metaKey) {
        Usermeta meta = userService.getUserMeta(user.getID(), metaKey);
        if (meta == null) {
            meta = new Usermeta();
            meta.setUserId(user.getID());
            meta.setMetaKey(metaKey);
        }
        return meta;
    }

    /**
     * 根据元数据键设置值
     */
    private void setMetaValueByKey(Usermeta meta, String metaKey, String value) {
        switch (metaKey) {
            case Usermeta.first_name:
                meta.setFirstName(value);
                break;
            case Usermeta.last_name:
                meta.setLastName(value);
                break;
            case Usermeta.nickname:
                meta.setNickname(value);
                break;
            case Usermeta.locale:
                meta.setLocale(value);
                break;
            case Usermeta.description:
                meta.setDescription(value);
                break;
            case Usermeta.admin_color:
                meta.setAdminColor(value);
                break;
            case Usermeta.rich_editing:
                meta.setRichEditing(value);
                break;
            case Usermeta.syntax_highlighting:
                meta.setSyntaxHighlighting(value);
                break;
            case Usermeta.comment_shortcuts:
                meta.setCommentShortcuts(value);
                break;
            case Usermeta.show_admin_bar_front:
                meta.setShowAdminBarFront(value);
                break;
            case Usermeta.simple_local_avatar:
                meta.setSimpleLocalAvatar(value);
                break;
            default:
                meta.setMetaValue(value);
                break;
        }
    }

    /**
     * 更新用户缓存
     */
    private void updateUserCache(Users user) {
        try {
            String sessionId = getSessionId(Users.sessionIdName);
            if (StrKit.notBlank(sessionId)) {
                CacheKit.put(Users.loginUserCacheName, sessionId, user);
                log.debug("用户缓存更新成功，用户ID: {}, 会话ID: {}",
                        user.getID(), hideSensitiveInfo(sessionId, 8, 4));
            }
        } catch (Exception e) {
            log.warn("更新用户缓存失败，用户ID: {}", user.getID(), e);
        }
    }
}